package org.darkgem.imageloader;

import android.content.Context;
import android.graphics.Bitmap;
import android.os.Handler;
import android.os.Looper;
import android.util.Log;
import android.view.View;
import android.view.ViewGroup;
import android.widget.ImageView;
import org.darkgem.imageloader.displayer.BitmapDisplayer;
import org.darkgem.imageloader.vendor.support.DefaultVendor;
import org.darkgem.imageloader.vendor.LoadListener;
import org.darkgem.imageloader.vendor.Vendor;

import java.lang.reflect.Field;
import java.util.LinkedList;
import java.util.List;
import java.util.Map;
import java.util.concurrent.ConcurrentHashMap;

public final class ImageLoader {
    static volatile ImageLoader instance;
    //是否已经初始化
    boolean initialized = false;
    //资源提供者
    Vendor vendor = null;
    //任务管理器
    Map<Integer, Task> taskMap = null;
    Handler handler;
    /**
     * 默认图片显示配置
     */
    DisplayImageOptions defaultDisplayImageOptions = null;

    /**
     * 默认进度监听器
     */
    ImageLoadListener defaultImageLoadListener = new ImageLoadListener() {
        /**
         * 开始加载
         */
        @Override
        public void onLoadStart() {

        }

        @Override
        public void onLoadSuccess(Bitmap[] bitmap) {
        }

        @Override
        public void onLoadFailed(Exception e) {
        }

        @Override
        public void onLoadProgress(int pg) {
        }

        /**
         * 被取消
         */
        @Override
        public void onLoadCancel() {

        }
    };

    /**
     * 单例模式
     */
    public static ImageLoader getInstance() {
        if (instance == null) {
            synchronized (ImageLoader.class) {
                if (instance == null) {
                    instance = new ImageLoader();
                }
            }
        }
        return instance;
    }

    /**
     * 读取ImageView的属性
     */
    private static int getImageViewFieldValue(Object object, String fieldName) {
        int value = 0;
        try {
            Field field = ImageView.class.getDeclaredField(fieldName);
            field.setAccessible(true);
            int fieldValue = (Integer) field.get(object);
            if (fieldValue > 0 && fieldValue < Integer.MAX_VALUE) {
                value = fieldValue;
            }
        } catch (Exception e) {
            Log.e(ImageLoader.class.getName(), e.getMessage(), e);
        }
        return value;
    }

    /**
     * 读取图片的大小
     */
    private static int getImageViewWidth(ImageView imageView, int defaultWidth) {

        int width = 0;
        ViewGroup.LayoutParams params = imageView.getLayoutParams();
        if (params != null && params.width != ViewGroup.LayoutParams.WRAP_CONTENT) {
            width = imageView.getWidth(); // Get actual image width
        }
        if (width <= 0 && params != null) {
            width = params.width; // Get layout width parameter
        }
        if (width <= 0) {
            width = getImageViewFieldValue(imageView, "mMaxWidth"); // Check maxWidth parameter
        }
        if (width <= 0) {
            width = imageView.getMeasuredWidth();
        }
        if (width <= 0) {
            int w = View.MeasureSpec.makeMeasureSpec(0, View.MeasureSpec.UNSPECIFIED);
            int h = View.MeasureSpec.makeMeasureSpec(0, View.MeasureSpec.UNSPECIFIED);
            imageView.measure(w, h);
            width = imageView.getMeasuredWidth();
        }
        if (width <= 0) {
            width = defaultWidth;
        }
        return width;
    }

    /**
     * 读取图片的大小
     */
    private static int getImageViewHeight(ImageView imageView, int defaultHeight) {
        int height = 0;
        ViewGroup.LayoutParams params = imageView.getLayoutParams();
        if (params != null && params.height != ViewGroup.LayoutParams.WRAP_CONTENT) {
            height = imageView.getHeight(); // Get actual image height
        }
        if (height <= 0 && params != null) {
            height = params.height; // Get layout height parameter
        }
        if (height <= 0) {
            height = getImageViewFieldValue(imageView, "mMaxHeight"); // Check maxHeight parameter
        }
        if (height <= 0) {
            height = imageView.getMeasuredHeight();
        }
        if (height <= 0) {
            int w = View.MeasureSpec.makeMeasureSpec(0, View.MeasureSpec.UNSPECIFIED);
            int h = View.MeasureSpec.makeMeasureSpec(0, View.MeasureSpec.UNSPECIFIED);
            imageView.measure(w, h);
            height = imageView.getMeasuredHeight();
        }
        if (height <= 0) {
            height = defaultHeight;
        }
        return height;

    }

    /**
     * 初始化ImageLoader对象, 且只能调用一次
     */
    synchronized public void init(Context context, DisplayImageOptions options, Vendor vendor) {
        if (this.initialized) {
            throw new RuntimeException("init() method is called");
        }
        //表示已经初始化
        this.initialized = true;
        if (options == null) {
            options = new DisplayImageOptions.Builder(context).build();
        }
        if (vendor == null) {
            //构造默认vendor
            vendor = new DefaultVendor(context);
        }
        this.defaultDisplayImageOptions = options;
        this.vendor = vendor;
        this.handler = new Handler(Looper.getMainLooper());
        this.taskMap = new ConcurrentHashMap<Integer, Task>();
    }

    /**
     * 指定uri的图片显示到view中, 使用默认 显示选项
     *
     * @param uri  图片地址
     * @param view ImageView对象
     */
    public void displayImage(String uri, ImageView view) {
        displayImage(new String[]{uri}, view, null, null);
    }

    /**
     * 指定uri的图片显示到view中, 使用默认 显示选项
     *
     * @param uri      图片地址
     * @param view     ImageView对象
     * @param listener 加载监听器
     */
    public void displayImage(String uri, ImageView view, ImageLoadListener listener) {
        displayImage(new String[]{uri}, view, null, listener);
    }

    /**
     * 指定uri的图片显示到view中
     *
     * @param uri      图片地址
     * @param view     ImageView对象
     * @param options0 显示选项
     */
    public void displayImage(String uri, final ImageView view, DisplayImageOptions options0) {
        displayImage(new String[]{uri}, view, options0, null);
    }

    /**
     * 指定uri的图片显示到view中
     *
     * @param uri      图片地址
     * @param view     ImageView对象
     * @param options0 显示选项
     * @param listener 加载监听器
     */
    public void displayImage(String uri, final ImageView view, DisplayImageOptions options0, ImageLoadListener listener) {
        displayImage(new String[]{uri}, view, options0, listener);
    }

    /**
     * 指定uri的图片显示到view中
     *
     * @param uris 图片地址
     * @param view ImageView对象
     */
    public void displayImage(String[] uris, final ImageView view) {
        displayImage(uris, view, null, null);
    }

    /**
     * 指定uri的图片显示到view中
     *
     * @param uris     图片地址
     * @param view     ImageView对象
     * @param listener 加载监听器
     */
    public void displayImage(String[] uris, final ImageView view, ImageLoadListener listener) {
        displayImage(uris, view, null, listener);
    }

    /**
     * 指定uri的图片显示到view中
     *
     * @param uris      图片地址
     * @param imageView ImageView对象
     * @param options   显示选项
     */
    public void displayImage(String[] uris, final ImageView imageView, DisplayImageOptions options) {
        displayImage(uris, imageView, options, null);
    }

    /**
     * 指定uri的图片显示到view中
     *
     * @param uris      图片地址
     * @param imageView ImageView对象
     * @param options0  显示选项
     * @param listener  加载监听器
     */
    public void displayImage(String[] uris, final ImageView imageView,
                             DisplayImageOptions options0, ImageLoadListener listener) {
        if (!initialized) {
            throw new RuntimeException("init() method Don't called");
        }
        List<String> uriList = new LinkedList<String>();
        //参数检测
        if (imageView == null) {
            return;
        }
        //默认显示配置
        if (options0 == null) {
            options0 = defaultDisplayImageOptions;
        }
        //默认监听器
        if (listener == null) {
            listener = defaultImageLoadListener;
        }
        //注意, 这个参数为只读
        final DisplayImageOptions options = options0;
        if (uris == null) {
            if (options.getImageResForEmptyUri() > 0) {
                uriList.add("drawable://" + options.getImageResForEmptyUri());
            }
        } else {
            for (String uri : uris) {
                if (uri == null && options.getImageResForEmptyUri() > 0) {
                    //如果uri为空, 并且配置了 为空的时候, 图片显示的样式, 则使用默认图片
                    uri = "drawable://" + options.getImageResForEmptyUri();
                }
                if (uri != null) {
                    uriList.add(uri);
                }
            }
        }
        //关闭之前的显示任务
        taskMap.remove(System.identityHashCode(imageView));
        //如果URI为空, 则把对应ImageView 置空, 并且返回
        if (uriList.size() == 0) {
            imageView.setImageBitmap(null);
            return;
        }
        //目前为止, 所有的参数都有效, 并且关闭了 之前在这个ImageView上的任务
        //配置图片大小参数
        final int suggestWidth = getImageViewWidth(imageView, options.getWidth());
        final int suggestHeight = getImageViewHeight(imageView, options.getHeight());
        //加入任务队列
        final Task task = new Task(uriList.size(), listener);
        taskMap.put(System.identityHashCode(imageView), task);
        //开始加载
        task.listener.onLoadStart();
        //批量加载图片
        for (String uri : uriList) {
            //加载
            vendor.loadImage(uri, suggestWidth, suggestHeight, options.getConfig(), options.isCacheInMemory(), new LoadListener() {
                @Override
                public void onLoadSuccess(final Bitmap bitmap) {
                    Execute execute = new Execute(taskMap, task, bitmap, imageView, options.getDisplayer(), suggestWidth, suggestHeight);
                    //判断线程是否为主线程
                    if (Looper.myLooper() != null && Looper.myLooper() == Looper.getMainLooper()) {
                        execute.run();
                    } else {
                        //在主线程中运行
                        handler.post(execute);
                    }
                }

                @Override
                public void onLoadFailed(Exception e) {
                    Execute execute = new Execute(taskMap, task, null, imageView, options.getDisplayer(), suggestWidth, suggestHeight);
                    //判断线程是否为主线程
                    if (Looper.myLooper() != null && Looper.myLooper() == Looper.getMainLooper()) {
                        execute.run();
                    } else {
                        //在主线程中运行
                        handler.post(execute);
                    }
                }

                @Override
                public void onLoadProgress(final int current, final int total) {
                    //判断线程是否为主线程
                    if (Looper.myLooper() != null && Looper.myLooper() == Looper.getMainLooper()) {
                        task.listener.onLoadProgress(current / total);
                    } else {
                        //在主线程中运行
                        handler.post(new Runnable() {
                            @Override
                            public void run() {
                                task.listener.onLoadProgress((current * 100) / total);
                            }
                        });
                    }
                }
            });
        }

    }

    /**
     * 获取资源提供者
     */
    public <T extends Vendor> T getVendor() {
        return (T) vendor;
    }

    /**
     * 任务
     */
    static class Task {
        //总共需要多少图片,才能完成本次任务
        int totalImageSize;
        //当前已经加载/失败的图片数量
        int currentImageSize;
        //可以使用的图片, 注意当任务失败/完成后, 清理资源
        List<Bitmap> bitmapList;
        //加载进度监听器
        ImageLoadListener listener;

        public Task(int totalImageSize, ImageLoadListener listener) {
            this.totalImageSize = totalImageSize;
            this.currentImageSize = 0;
            this.bitmapList = new LinkedList<Bitmap>();
            this.listener = listener;
        }

        /**
         * 该任务的图片是否搜集完毕
         */
        public boolean finish() {
            if (totalImageSize <= currentImageSize) {
                return true;
            }
            return false;
        }

        /**
         * 获取任务的所有有效图片
         */
        public Bitmap[] getBitmapArray() {
            Bitmap[] ret = bitmapList.toArray(new Bitmap[0]);
            return ret;
        }

        /**
         * 添加一个完成的bitmap 到任务中
         */
        public void collect(Bitmap bitmap) {
            if (bitmap != null) {
                bitmapList.add(bitmap);
            }
            currentImageSize++;
        }
    }

    /**
     * 任务执行器
     */
    static class Execute implements Runnable {
        boolean cancel = false;
        Map<Integer, Task> taskMap;
        Task task;
        Bitmap bitmap;
        ImageView view;
        BitmapDisplayer displayer;
        int suggestWidth;
        int suggestHeight;

        public Execute(Map<Integer, Task> taskMap, Task task, Bitmap bitmap,
                       ImageView view, BitmapDisplayer displayer,
                       int suggestWidth, int suggestHeight) {
            this.taskMap = taskMap;
            this.task = task;
            this.bitmap = bitmap;
            this.view = view;
            this.displayer = displayer;
            this.suggestWidth = suggestWidth;
            this.suggestHeight = suggestHeight;
        }

        /**
         * Starts executing the active part of the class' code. This method is
         * called when a thread is started that has been created with a class which
         * implements {@code Runnable}.
         */
        @Override
        public void run() {
            try {
                //检测该任务是否已经被取消
                Task t = taskMap.get(System.identityHashCode(view));
                if (t == null || t != task) {
                    if (!cancel) {
                        cancel = true;
                        //提示取消加载
                        task.listener.onLoadCancel();
                    }
                    return;
                }
                //加入图片集合
                task.collect(bitmap);
                //如果图片大于1, 则加载数量为进度条
                if (task.totalImageSize > 1) {
                    task.listener.onLoadProgress((task.currentImageSize * 100) / task.totalImageSize);
                }
                //检测是否到达目标数量
                if (task.finish()) {
                    Bitmap[] bitmaps = task.getBitmapArray();
                    if (bitmaps.length != 0) {
                        displayer.display(bitmaps, view, suggestWidth, suggestHeight);
                        //加载成功
                        task.listener.onLoadSuccess(bitmaps);
                    } else {
                        //加载失败
                        task.listener.onLoadFailed(new Exception("No Collect Bitmap"));
                    }
                    //从任务队列删除
                    taskMap.remove(System.identityHashCode(view));
                }
            } catch (Exception e) {
                Log.e(ImageLoader.class.getName(), e.getMessage(), e);
                //加载失败
                task.listener.onLoadFailed(e);
                //如果发生任何异常, 则剔除这个任务
                taskMap.remove(System.identityHashCode(view));
            }
        }
    }


}
